﻿#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/ioctl.h>
#include <net/if.h>

#include <linux/can.h>
#include <linux/can/raw.h>
#include "libsocketcan.h"
#include "can.h"



struct can_handle*  can_open(const char *dev, int bitrate, int filter_num, struct canmsg_filter *filter_tab)
{
	struct ifreq ifr;
	struct sockaddr_can addr;
	int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
	int state, num, i;
	int s;
	struct can_handle *handle;
	struct can_filter *actual_filter;	
	
	if (bitrate < 10000 || bitrate > 1000000) {
		printf("%s: error bitrate %ubps\n", dev, bitrate);
		return NULL;
	}
	printf("%s: bitrate %ubps\n", dev, bitrate);
	
	if (can_get_state(dev, &state) < 0) {
		printf("%s: failed to get state \n", dev);
		return NULL;
	}
	
	if (state != CAN_STATE_STOPPED && can_do_stop(dev) < 0) {
		printf("%s: failed to stop\n", dev);
		return NULL;
	}
	
	if (can_set_bitrate(dev, bitrate) < 0) {
		printf("failed to set bitrate of %s to %u\n",
			dev, bitrate);
		return NULL;
	}
	
	if (can_do_start(dev) < 0) {
		printf("%s: failed to start\n", dev);
		return NULL;
	}
	
	if ( (s = socket(family, type, proto)) < 0) {
		perror("socket");
		return NULL;
	}

	addr.can_family = family;
	strncpy(ifr.ifr_name, dev, 8);
	ioctl(s, SIOCGIFINDEX, &ifr);
	addr.can_ifindex = ifr.ifr_ifindex;
	
	if ( (s = socket(family, type, proto)) < 0) {	
		printf("Create socket of %s error\n", dev);
		return NULL;
	}
	
	num = filter_num;
	if (num == 0)
		num = 1;
	else if (num > 64)
		num = 64;

	actual_filter = (struct can_filter *)malloc(sizeof(struct can_filter) * num);
	if (actual_filter == NULL)
	{
	    printf("malloc can filter failed\n");
	    close(s);		
		return NULL;
	}
	
	if (filter_num == 0) {
		actual_filter->can_id = 0;
		actual_filter->can_mask = CAN_RTR_FLAG;
	} else {
		for (i = 0; i < num; i++)
		{
			actual_filter[i].can_mask = (filter_tab->can_mask & CAN_EXTEND_MASK) | CAN_EFF_FLAG | CAN_RTR_FLAG;
			if (filter_tab->can_id & CAN_EXTEND_FLAG)
				actual_filter[i].can_id = (filter_tab->can_id & CAN_EXTEND_MASK) | CAN_EFF_FLAG;
			else
				actual_filter[i].can_id = filter_tab->can_id & CAN_EXTEND_MASK;
			filter_tab++;
		}
	}
	
	if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, actual_filter,
			       sizeof(struct can_filter) * num) != 0) {
		printf("set %s filter failed\n", dev);
	    close(s);
	    free(actual_filter);		
		return NULL;
	}
	free(actual_filter);
	
	/* struct timeval timeout = {3,0};
	setsockopt(s, SOL_CAN_RAW, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval)); */
	
	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		printf("%s: bind failed\n", dev);
	    close(s);		
		return NULL;
	}
	
	handle = (struct can_handle*)malloc(sizeof(struct can_handle));
    if (handle == NULL) {
		close(s);
    	return NULL;
	}
	
	handle->socket = s;
	strncpy(handle->dev_name, dev, 32);

	return handle;
}


void  can_close(struct can_handle *handle)
{
	int state;

	if (handle == NULL)
		return;
	close(handle->socket);
	if (can_get_state(handle->dev_name, &state) < 0) {
		printf("%s: failed to get state \n", handle->dev_name);
		free(handle);
		return;
	}
	
	if (state != CAN_STATE_STOPPED && can_do_stop(handle->dev_name) < 0)
		printf("%s: failed to stop\n", handle->dev_name);
	free(handle);
}


int  can_write(void *ctx, unsigned int id, unsigned char *data, int bytes)
{	
	struct can_frame frame;
	struct can_handle *handle = (struct can_handle*)ctx;
	
	if (handle == NULL)
		return -1;
	if (bytes > 8) bytes = 8;	
	frame.can_id = id;
	memcpy(frame.data, data, bytes);
	frame.can_dlc = bytes;
	return write(handle->socket, &frame, sizeof(frame));
}
